﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace BadHabit.WPFTools {

    /// <summary>
    /// Microsoft Datagrid has some limitations, such as:
    /// 
    /// - Navigation keys when at the EditMode
    /// - Set focus on edit control at templatecollumns
    /// - Is the datagrid at EditMode?
    /// 
    /// To solve those issues we create this class.
    /// </summary>
    public class DataGrid : Microsoft.Windows.Controls.DataGrid {


        internal static readonly DependencyPropertyKey IsEditingPropertyKey = DependencyProperty.RegisterReadOnly(
            "IsEditing",
            typeof(Boolean),
            typeof(DataGrid),
            null);

        /// <summary>
        /// IEditing Dependency Property.
        /// </summary>
        public static readonly DependencyProperty IsEditingProperty = IsEditingPropertyKey.DependencyProperty;


        /// <summary>
        /// Returns true if there is a cell being editing. This is a Dependency Property.
        /// </summary>
        public Boolean IsEditing {
            get {
                return (Boolean) GetValue(IsEditingProperty);     
            }
            private set {
                SetValue(IsEditingPropertyKey, value);
            }
        }

        /// <summary>
        /// Sets and Gets whenever should use navigations extensions or not.
        /// </summary>
        public Boolean UseNavigationExtensions { get; set; }

        /// <summary>
        /// Whenever a cell begins to be edited set the IsEditing Property.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnBeginningEdit(Microsoft.Windows.Controls.DataGridBeginningEditEventArgs e) {
            base.OnBeginningEdit(e);
            IsEditing = true;            
        }

        /// <summary>
        /// Whenever a cell ends to be edited set the IsEditing Property.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnCellEditEnding(Microsoft.Windows.Controls.DataGridCellEditEndingEventArgs e) {
            base.OnCellEditEnding(e);
            IsEditing = false;            
        }

        /// <summary>
        /// Whenever a cell starts the edit mode, set focus on the first control of the cell that have TABSTOP.
        /// This is a workaround for templatecolumns.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreparingCellForEdit(Microsoft.Windows.Controls.DataGridPreparingCellForEditEventArgs e) {
            base.OnPreparingCellForEdit(e);
            if (!UseNavigationExtensions)
                return;
            Control control = GetNextTabStopControlObjectInVisualTree(e.EditingElement);
            if (control != null && control.IsEnabled && control.IsTabStop)
                control.Focus();
        }

        /// <summary>
        /// Now you can use UP/DOWN arrows even at the edit mode.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreviewKeyDown(KeyEventArgs e) {
            base.OnPreviewKeyDown(e);
            if (!UseNavigationExtensions)
                return;

            // If is editing and UP/DOWN was presees move to the up/down rows
            if (IsEditing) {

                UIElement focused = Keyboard.FocusedElement as UIElement;
                if (focused == null)
                    return;

                if (focused is System.Windows.Controls.ComboBox)
                    return;

                if (e.Key == Key.Down) {
                    CommitEdit();
                    focused.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down));
                }
                if (e.Key == Key.Up) {
                    CommitEdit();
                    focused.MoveFocus(new TraversalRequest(FocusNavigationDirection.Up));
                }

            } else {

                // This is a work around for get focus on Template columns.
                if (e.Key != Key.Left && e.Key != Key.Right && e.Key != Key.Down && e.Key != Key.Up) {                    
                    if (!(CurrentColumn is Microsoft.Windows.Controls.DataGridTemplateColumn))
                        return;
                    BeginEdit();
                }

            }
        }



        public static Control GetNextTabStopControlObjectInVisualTree(System.Windows.DependencyObject dpob) {
            int count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(dpob);
            for (int i = 0; i < count; i++) {
                System.Windows.DependencyObject child = System.Windows.Media.VisualTreeHelper.GetChild(dpob, i);
                Control childControl = child as Control;
                if (childControl != null && childControl.Focusable && childControl.IsTabStop)
                    return childControl;

                childControl = GetNextTabStopControlObjectInVisualTree(child);
                if (childControl != null)
                    return childControl;
            }
            return null;
        }



    }
}
